【神经网络】(3) 卷积神经网络(CNN),案例:动物三分类,附python完整代码

您所在的位置:网站首页 tensorflow cnn图像分类 【神经网络】(3) 卷积神经网络(CNN),案例:动物三分类,附python完整代码

【神经网络】(3) 卷积神经网络(CNN),案例:动物三分类,附python完整代码

2023-12-14 09:56| 来源: 网络整理| 查看: 265

各位同学好,今天和大家分享一下TensorFlow2.0深度学习中卷积神经网络的案例。现在有猫、狗、熊猫图片一千张,构建卷积神经网络实现图像的分类预测。

1. 数据加载

将训练测试数据划分好后放在同一个文件目录下,使用tf.keras.preprocessing.image_dataset_from_directory()函数构造数据集。函数的具体用法见:tf.keras.preprocessing.image_dataset_from_directory_自在独行的博客-CSDN博客_image_dataset_from_directory

对训练数据和验证数据进行one-hot编码,便于计算损失,读入图像时统一图片大小size为128*128。batch为64,每次迭代从中取64个样本。class_names中保存的是根据文件夹名称生成的标签。

# 三分类,卷积神经网络 import numpy as np import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers,optimizers,datasets,Sequential import os # 设置一下输出框打印的内容 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # '2'输出栏只打印error信息,其他乱七八糟的信息不打印 #(1)数据获取 # 加载训练集数据 filepath1 = 'C:/Users/admin/.../train' train_ds = tf.keras.preprocessing.image_dataset_from_directory( filepath1, label_mode='categorical', # "int", "categorical"表示onehot, "binary", or None seed=123, image_size=(128, 128), # resize图片大小 batch_size=64) # 加载验证集数据 filepath2 = 'C:/Users/admin/.../new_data/val' val_ds = tf.keras.preprocessing.image_dataset_from_directory( filepath2, label_mode='categorical', seed=123, image_size=(128, 128), batch_size=64) # 加载测试集数据 filepath3 = 'C:/Users/.../new_data/test' test_ds = tf.keras.preprocessing.image_dataset_from_directory( filepath3, label_mode='int', seed=123, image_size=(128, 128), batch_size=64) # 类别名称 class_names = train_ds.class_names print('类别有:',class_names) # 类别有: ['cats', 'dogs', 'panda'] 2. 数据预处理

使用.map()对dataset中的数据进行processing函数中的操作,对每个点的像素值从[0,255]变成[-1,1],.shuffle()对数据集重新洗牌打散,但不改变x和y之间的对应关系。

train_ds.take(1) 是指从训练集数据集中取出1个batch的数据,返回值img存放图像数据,label存放图像的标签。

#(2)数据预处理 def processing(image, label): image = 2 * tf.cast(image, tf.float32) / 255.0 - 1 #[-1,1]之间 label = tf.cast(label, tf.int32) # 修改数据类型 return (image, label) train_ds = train_ds.map(processing).shuffle(10000) #洗牌 val_ds = val_ds.map(processing).shuffle(10000) test_ds = test_ds.map(processing).shuffle(10000) #(2)数据检查 for img, label in train_ds.take(1): # 取出一个batch的数据,一个batch有64个样本 print('img.shape:', img.shape) # img.shape: (64, 128, 128, 3) print('label.shape:', label.shape) # label.shape: (64, 3) # 数据集展示 import matplotlib.pyplot as plt for img,label in train_ds.take(1): #取一个batch for i in range(15): plt.subplot(3,5,i+1) plt.imshow(img[i]) # 每张图像的shape为(4, 256, 256, 3) plt.xticks([]) # 不显示xy轴坐标刻度 plt.yticks([]) plt.show()

预处理后的图像展示结果如下:

3. 网络构建

这里构造一个6层的神经网络,使用Sequential()容器堆叠网络各层,layers.Conv2D()构造卷积层,卷积核size为3*3。layers.MaxPool2D()构造池化层,采用最大池化方法。指定padding='same'填充图像,在传播过程中保证生成的特征图的size不变,只改变其channel。指定layers.Dropout(0.2)每次迭代该层每个神经元都有20%的概率被杀死,防止网络出现过拟合现象。

在卷积池化层和全连接层之间需要指定一个Flatten层layers.Flatten(),输入至全连接层的图像需要是一个二维tensor,假设卷积池化层输出的shape为[b,1,1,64],那么传入全连接层的shape需要w是[b,64]

#(3)网络构建 # ==1== 卷积和池化层,2次卷积1次池化 network = Sequential() # unit1 network.add(layers.Conv2D(32, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu)) network.add(layers.Conv2D(32, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu)) network.add(layers.MaxPool2D(pool_size=[2,2], strides=2, padding='same')) # unit2 network.add(layers.Conv2D(64, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu)) network.add(layers.Conv2D(64, kernel_size=[3,3], strides=1, padding='same', activation=tf.nn.relu)) network.add(layers.MaxPool2D(pool_size=[2,2], strides=2, padding='same')) # dropout层 network.add(layers.Dropout(0.2)) #每个神经元都有0.2的概率被杀死 # ==2== Flatten层,连接卷积池化层和全连接层 network.add(layers.Flatten()) # ==3== 全连接层 network.add(layers.Dense(128, activation=tf.nn.relu)) network.add(layers.Dense(3)) # 输出层logits层 # ==4== 指定输入层 network.build(input_shape=[None, 128, 128, 3]) # ==5== 查看网络结构 network.summary()

网络结构如下,param代表该层网络拥有的参数个数

Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 128, 128, 32) 896 conv2d_2 (Conv2D) (None, 128, 128, 32) 9248 max_pooling2d_1 (MaxPoolin (None, 64, 64, 32) 0 g2D) conv2d_3 (Conv2D) (None, 64, 64, 64) 18496 conv2d_4 (Conv2D) (None, 64, 64, 64) 36928 max_pooling2d_2 (MaxPoolin (None, 32, 32, 64) 0 g2D) dropout_1 (Dropout) (None, 32, 32, 64) 0 flatten_1 (Flatten) (None, 65536) 0 dense_1 (Dense) (None, 128) 8388736 dense_2 (Dense) (None, 3) 387 ================================================================= Total params: 8,454,691 Trainable params: 8,454,691 Non-trainable params: 0 _________________________________________________________________ 4. 网络配置

采用学习率指数衰减的方法方法,tf.keras.optimizers.schedules.ExponentialDecay(),起初梯度变化大一点能更快接近目标,后续梯度变化不断减小,越来越逼近最优点。设置早停策略,因为神经网络在不断迭代的过程中,准确率不会一直在上升,如果找到某一极值点,且后续多次迭代过程中,网络效果没有变的更优的迹象,就使用之前的极值点的结果作为最优解。

#(4)网络配置 # 设置动态学习率指数衰减 exponential_decay = tf.keras.optimizers.schedules.ExponentialDecay( initial_learning_rate=0.001, #初始学习率 decay_steps=2, # 衰减步长 decay_rate=0.96) # 衰减率 # 编译 network.compile(optimizer=optimizers.Adam(learning_rate=exponential_decay), loss=tf.losses.CategoricalCrossentropy(from_logits=True), # 交叉熵损失 metrics=['accuracy']) # 准确率指标 # 早停策略 early_stopping = keras.callbacks.EarlyStopping( monitor = 'val_acc', # 验证集的准确率作为指标 patience = 10, # 最多忍受多少个次循环没有改进 restore_best_weights = True) # 发生早停时,自动寻找最优的monitor参数 5. 模型训练 #(5)网络训练 # 指定训练集、验证集、迭代次数 # 训练目标和验证目标需要时one_hot编码后的 model = network.fit(train_ds, # 训练集 validation_data=val_ds, # 验证集 epochs=10, # 迭代多少次 callbacks= early_stopping, # 回调函数,在训练过程中的适当时机被调用 shuffle = True, # 每轮迭代之前洗牌 verbose = 1 # 0为不在标准输出流输出日志信息,1:显示进度条,2:每个epoch输出一行记录 )

由于时间关系,这里就简单循环10次,效果如下

Epoch 1/10 33/33 [==============================] - ETA: 0s - loss: 1.1605 - accuracy: 0.4527 WARNING:tensorflow:Early stopping conditioned on metric `val_acc` which is not available. Available metrics are: loss,accuracy,val_loss,val_accuracy 33/33 [==============================] - 75s 2s/step - loss: 1.1605 - accuracy: 0.4527 - val_loss: 0.8374 - val_accuracy: 0.5796 #.................# #.................# Epoch 10/10 33/33 [==============================] - ETA: 0s - loss: 0.6362 - accuracy: 0.6985 WARNING:tensorflow:Early stopping conditioned on metric `val_acc` which is not available. Available metrics are: loss,accuracy,val_loss,val_accuracy 33/33 [==============================] - 96s 3s/step - loss: 0.6362 - accuracy: 0.6985 - val_loss: 0.6821 - val_accuracy: 0.6415 6. 模型评估

比较网络训练集和验证集上的准确率和损失,绘图比较

#(6)模型评估 # ==1== 计算准确率 train_acc = model.history['accuracy'] val_acc = model.history['val_accuracy'] # ==2== 损失 train_loss = model.history['loss'] val_loss = model.history['val_loss'] # ==3== 曲线图 epochs_range = range(len(train_acc)) # 横坐标,网络循环了几次 # 准确率曲线 plt.figure(figsize=(10,5)) plt.subplot(1,2,1) plt.plot(epochs_range, train_acc, label='Training_acc') plt.plot(epochs_range, val_acc, label='validation_acc') plt.legend() plt.title('Accuracy') # 损失曲线 plt.subplot(1,2,2) plt.plot(epochs_range, train_loss, label='Training_loss') plt.plot(epochs_range, val_loss, label='validation_loss') plt.legend() plt.title('Loss')

如图所示训练集和验证集的损失都逐渐下降,随着迭代次数的增加,效果会更好,但要防止过拟合的现象出现。

7. 预测

采用测试集中的图像数据对网络进行预测,network.predict()得到输入图像分别属于三个分类的数值,返回numpy类型,使用np.argmax()找到最大值的索引,该索引对应的class_names标签就是预测得到的该图像所属的分类。

#(7)预测 test_pred = [] test_target = [] for images, targets in test_ds: #取一个batch的测试集生成混淆矩阵 for image, label in zip(images, targets): # 每次从batch中取出一组 # 需要给图片增加一个维度 img_array = tf.expand_dims(image, axis=0) # 使用模型预测图片中的动物 prediction = network.predict(img_array) # 预测结果是预测值最大值索引对应的位置 test_pred.append(class_names[np.argmax(prediction)]) # 保存真实值的标签 test_target.append(class_names[label]) # label没有做onehot编码 print('测试结果:',test_pred[:10]) print('真实结果:',test_target[:10]) #(8)混淆矩阵 from sklearn.metrics import confusion_matrix import seaborn as sns import pandas as pd plt.rcParams['font.sans-serif'] = ['SimSun'] #宋体 plt.rcParams['font.size'] = 15 #设置字体大小 # 生成混淆矩阵 conf_numpy = confusion_matrix(test_target, test_pred) # 将矩阵转化为 DataFrame conf_df = pd.DataFrame(conf_numpy, index=class_names ,columns=class_names) plt.figure(figsize=(8,7)) sns.heatmap(conf_df, annot=True, fmt="d", cmap="BuPu") plt.title('混淆矩阵') plt.ylabel('真实值') plt.xlabel('预测值')

输出的前10张图片的预测结果如下:

测试结果: ['panda', 'dogs', 'cats', 'cats', 'panda', 'panda', 'panda', 'panda', 'dogs', 'panda'] 真实结果: ['panda', 'dogs', 'dogs', 'cats', 'panda', 'panda', 'panda', 'panda', 'cats', 'panda']

为了更加清晰的展示预测值和真实值的关系,构建混淆矩阵,如图。可见一个6层的卷积网络经过10次循环后,对熊猫的预测精度最高,对狗的预测精度较低,需要增加网络层数和循环次数。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3